From 5e09eaa6898650bdfe84126f4e21586dddda2fad Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Tue, 11 Jan 2005 11:41:56 +0000 Subject: [PATCH] bitkeeper revision 1.1159.218.1 (41e3bb84y5sV55DN1DoraDUQU096Qw) More privileged-instruction emulation. We now handle CLTS and MOV to/from CRn. --- xen/arch/x86/memory.c | 51 ++++++----- xen/arch/x86/traps.c | 144 ++++++++++++++++++++++++++------ xen/include/asm-x86/mm.h | 2 + xen/include/asm-x86/processor.h | 3 + 4 files changed, 153 insertions(+), 47 deletions(-) diff --git a/xen/arch/x86/memory.c b/xen/arch/x86/memory.c index f1982eb6c0..d53ee4c107 100644 --- a/xen/arch/x86/memory.c +++ b/xen/arch/x86/memory.c @@ -937,12 +937,41 @@ int get_page_type(struct pfn_info *page, u32 type) } +int new_guest_cr3(unsigned long pfn) +{ + struct exec_domain *ed = current; + struct domain *d = ed->domain; + int okay, cpu = smp_processor_id(); + unsigned long old_base_pfn; + + okay = get_page_and_type_from_pagenr(pfn, PGT_l2_page_table, d); + if ( likely(okay) ) + { + invalidate_shadow_ldt(ed); + + percpu_info[cpu].deferred_ops &= ~DOP_FLUSH_TLB; + old_base_pfn = pagetable_val(ed->mm.pagetable) >> PAGE_SHIFT; + ed->mm.pagetable = mk_pagetable(pfn << PAGE_SHIFT); + + shadow_mk_pagetable(&ed->mm); + + write_ptbase(&ed->mm); + + put_page_and_type(&frame_table[old_base_pfn]); + } + else + { + MEM_LOG("Error while installing new baseptr %08lx", ptr); + } + + return okay; +} + static int do_extended_command(unsigned long ptr, unsigned long val) { int okay = 1, cpu = smp_processor_id(); unsigned int cmd = val & MMUEXT_CMD_MASK; unsigned long pfn = ptr >> PAGE_SHIFT; - unsigned long old_base_pfn; struct pfn_info *page = &frame_table[pfn]; struct exec_domain *ed = current; struct domain *d = ed->domain, *nd, *e; @@ -1003,25 +1032,7 @@ static int do_extended_command(unsigned long ptr, unsigned long val) break; case MMUEXT_NEW_BASEPTR: - okay = get_page_and_type_from_pagenr(pfn, PGT_l2_page_table, d); - if ( likely(okay) ) - { - invalidate_shadow_ldt(ed); - - percpu_info[cpu].deferred_ops &= ~DOP_FLUSH_TLB; - old_base_pfn = pagetable_val(ed->mm.pagetable) >> PAGE_SHIFT; - ed->mm.pagetable = mk_pagetable(pfn << PAGE_SHIFT); - - shadow_mk_pagetable(&ed->mm); - - write_ptbase(&ed->mm); - - put_page_and_type(&frame_table[old_base_pfn]); - } - else - { - MEM_LOG("Error while installing new baseptr %08lx", ptr); - } + okay = new_guest_cr3(pfn); break; case MMUEXT_TLB_FLUSH: diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index fed80f1f7e..61f8b8b90a 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -383,14 +383,30 @@ asmlinkage void do_machine_check(struct xen_regs *regs) fatal_trap(TRAP_machine_check, regs); } -asmlinkage int do_page_fault(struct xen_regs *regs) +static inline void propagate_page_fault(unsigned long addr, u16 error_code) { trap_info_t *ti; + struct exec_domain *ed = current; + struct trap_bounce *tb = &ed->thread.trap_bounce; + + ti = ed->thread.traps + 14; + tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE | TBF_EXCEPTION_CR2; + tb->cr2 = addr; + tb->error_code = error_code; + tb->cs = ti->cs; + tb->eip = ti->address; + if ( TI_GET_IF(ti) ) + ed->vcpu_info->evtchn_upcall_mask = 1; + + ed->mm.guest_cr2 = addr; +} + +asmlinkage int do_page_fault(struct xen_regs *regs) +{ unsigned long off, addr, fixup; struct exec_domain *ed = current; struct domain *d = ed->domain; extern int map_ldt_shadow_page(unsigned int); - struct trap_bounce *tb = &ed->thread.trap_bounce; int cpu = ed->processor; int ret; @@ -447,14 +463,7 @@ asmlinkage int do_page_fault(struct xen_regs *regs) if ( !GUEST_FAULT(regs) ) goto xen_fault; - ti = ed->thread.traps + 14; - tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE | TBF_EXCEPTION_CR2; - tb->cr2 = addr; - tb->error_code = regs->error_code; - tb->cs = ti->cs; - tb->eip = ti->address; - if ( TI_GET_IF(ti) ) - ed->vcpu_info->evtchn_upcall_mask = 1; + propagate_page_fault(addr, regs->error_code); return 0; xen_fault: @@ -497,45 +506,126 @@ asmlinkage int do_page_fault(struct xen_regs *regs) static int emulate_privileged_op(struct xen_regs *regs) { - u16 opcode; + extern long do_fpu_taskswitch(void); + extern void *decode_reg(struct xen_regs *regs, u8 b); - if ( get_user(opcode, (u16 *)regs->eip) || ((opcode & 0xff) != 0x0f) ) - return 0; + struct exec_domain *ed = current; + unsigned long *reg, eip = regs->eip; + u8 opcode; + + if ( get_user(opcode, (u8 *)eip) ) + goto page_fault; + eip += 1; + if ( (opcode & 0xff) != 0x0f ) + goto fail; - switch ( opcode >> 8 ) + if ( get_user(opcode, (u8 *)eip) ) + goto page_fault; + eip += 1; + + switch ( opcode ) { + case 0x06: /* CLTS */ + (void)do_fpu_taskswitch(); + break; + case 0x09: /* WBINVD */ - if ( !IS_CAPABLE_PHYSDEV(current->domain) ) + if ( !IS_CAPABLE_PHYSDEV(ed->domain) ) { DPRINTK("Non-physdev domain attempted WBINVD.\n"); - return 0; + goto fail; } wbinvd(); - regs->eip += 2; - return 1; - + break; + + case 0x20: /* MOV CR?, */ + if ( get_user(opcode, (u8 *)eip) ) + goto page_fault; + eip += 1; + if ( (opcode & 0xc0) != 0xc0 ) + goto fail; + reg = decode_reg(regs, opcode); + switch ( (opcode >> 3) & 7 ) + { + case 0: /* Read CR0 */ + *reg = + (read_cr0() & ~X86_CR0_TS) | + (test_bit(EDF_GUEST_STTS, &ed->ed_flags) ? X86_CR0_TS : 0); + break; + + case 2: /* Read CR2 */ + *reg = ed->mm.guest_cr2; + break; + + case 3: /* Read CR3 */ + *reg = pagetable_val(ed->mm.pagetable); + break; + + default: + goto fail; + } + break; + + case 0x22: /* MOV ,CR? */ + if ( get_user(opcode, (u8 *)eip) ) + goto page_fault; + eip += 1; + if ( (opcode & 0xc0) != 0xc0 ) + goto fail; + reg = decode_reg(regs, opcode); + switch ( (opcode >> 3) & 7 ) + { + case 0: /* Write CR0 */ + if ( *reg & X86_CR0_TS ) /* XXX ignore all but TS bit */ + (void)do_fpu_taskswitch; + break; + + case 2: /* Write CR2 */ + ed->mm.guest_cr2 = *reg; + break; + + case 3: /* Write CR3 */ + LOCK_BIGLOCK(ed->domain); + (void)new_guest_cr3(*reg); + UNLOCK_BIGLOCK(ed->domain); + break; + + default: + goto fail; + } + break; + case 0x30: /* WRMSR */ - if ( !IS_PRIV(current->domain) ) + if ( !IS_PRIV(ed->domain) ) { DPRINTK("Non-priv domain attempted WRMSR.\n"); - return 0; + goto fail; } wrmsr(regs->ecx, regs->eax, regs->edx); - regs->eip += 2; - return 1; + break; case 0x32: /* RDMSR */ - if ( !IS_PRIV(current->domain) ) + if ( !IS_PRIV(ed->domain) ) { DPRINTK("Non-priv domain attempted RDMSR.\n"); - return 0; + goto fail; } rdmsr(regs->ecx, regs->eax, regs->edx); - regs->eip += 2; - return 1; + break; + + default: + goto fail; } + regs->eip = eip; + return EXCRET_fault_fixed; + + fail: return 0; + + page_fault: + propagate_page_fault(eip, 0); + return EXCRET_fault_fixed; } asmlinkage int do_general_protection(struct xen_regs *regs) diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h index af2abb5a0a..05712d80c3 100644 --- a/xen/include/asm-x86/mm.h +++ b/xen/include/asm-x86/mm.h @@ -278,6 +278,8 @@ extern ptwr_info_t ptwr_info[]; void ptwr_flush(const int); int ptwr_do_page_fault(unsigned long); +int new_guest_cr3(unsigned long pfn); + #define __cleanup_writable_pagetable(_what) \ do { \ int cpu = smp_processor_id(); \ diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index bed1464bac..9c66c86ae7 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -485,6 +485,9 @@ struct mm_struct { unsigned long min_pfn; /* min host physical */ unsigned long max_pfn; /* max host physical */ + /* Virtual CR2 value. Can be read/written by guest. */ + unsigned long guest_cr2; + /* shadow mode status and controls */ unsigned int shadow_mode; /* flags to control shadow table operation */ pagetable_t shadow_table; -- 2.30.2